#region File Description
//-----------------------------------------------------------------------------
// GameplayScreen.cs
//
// Attack of the Crazy Pixels
// Copyright (c) VosSoft 2009
//-----------------------------------------------------------------------------
#endregion

#region Using Statements
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Xml;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Audio;
using Microsoft.Xna.Framework.Content;
using Microsoft.Xna.Framework.GamerServices;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;
using Microsoft.Xna.Framework.Media;
using Microsoft.Xna.Framework.Net;
using Microsoft.Xna.Framework.Storage;
#endregion

namespace Attack_of_the_Crazy_Pixels
{
    /// <summary>
    /// This screen implements the actual game logic.
    /// </summary>
    class GameplayScreen : GameScreen
    {
        #region Fields

        const float collisonDistanceBetweenTowers = 5.0f;
        const float collisonDistanceTowerPath = 20.0f;
        const float selectCursorRadius = 14.0f, selectCursorPulsation = 6.0f;
        const float textBlinkTime = 1.0f;

        ContentManager content;

        Texture2D circleTexture;
        SpriteFont gameFont, guiFont, arial, debugFont;

        AudioEngine audioEngine;
        WaveBank waveBank;
        SoundBank soundBank;
        //Cue trackCue;

        Circle towerCircle, selectCursor;
        float circleRotationFactor = 0.0f, currentSelectCursorPulsation = 0.0f;
        bool selectCursorPulsationDirection = false; // false = out, true = in

        Vector2 mousePosition = Vector2.Zero;

        Player player;

        List<TowerInfo> towers;
        TowerInfo currentTower;
        int towerIndex = 0;

        List<Level> levels;
        Level currentLevel;
        int levelIndex = 0;

        GameplaySate gameplayState = GameplaySate.Place;

        bool canTowerPlaceHere = false;
        Vector2 collisionPoint = Vector2.Zero;
        float currentTextBlinkTime = 0.0f;

        bool isPaused = false;
        bool isBulletTime = false;

        #endregion

        #region Initialization

        /// <summary>
        /// Constructor.
        /// </summary>
        public GameplayScreen()
        {
            TransitionOnTime = TimeSpan.FromSeconds(1.5);
            TransitionOffTime = TimeSpan.FromSeconds(0.5);

            player = new Player();

            Mouse.SetPosition(640, 360);
        }

        /// <summary>
        /// Load graphics content for the game.
        /// </summary>
        public override void LoadContent()
        {
            if (content == null)
            {
                content = new ContentManager(ScreenManager.Game.Services, "Content");
            }

            gameFont = content.Load<SpriteFont>(@"Fonts\game");
            guiFont = content.Load<SpriteFont>(@"Fonts\gui");
            arial = content.Load<SpriteFont>(@"Fonts\Arial");
            debugFont = content.Load<SpriteFont>(@"Fonts\debug");

            circleTexture = content.Load<Texture2D>(@"Textures\circle");
            Enemy.EnemyTexture = content.Load<Texture2D>(@"Textures\Enemies\Enemy");

            audioEngine = new AudioEngine(@"Content\Audio\GameAudio.xgs");
            waveBank = new WaveBank(audioEngine, @"Content\Audio\Wave Bank.xwb");
            soundBank = new SoundBank(audioEngine, @"Content\Audio\Sound Bank.xsb");

            selectCursor = new Circle(Vector2.Zero, selectCursorRadius, 16, false, 0.0f, 3.0f, Color.Black);

            LoadTowers(@"Content\Towers");
            if (towers.Count > 0)
            {
                currentTower = towers[0];
                towerCircle = new Circle(Vector2.Zero, towers[0].Range[0], 32, true, 0.0f, 2.0f, Color.Black);
            }
            else
            {
                ExitScreen();
                LoadingScreen.Load(ScreenManager, false, null, new BackgroundScreen(), new MainMenuScreen(),
                    new MessageBoxScreen("OMG !!!\n\nI Couldn't find any tower to load!\nWhat happend here? :(", false, false));
            }

            LoadLevels(@"Content\Levels");
            if (levels.Count > 0)
            {
                currentLevel = levels[0];
            }
            else
            {
                ExitScreen();
                LoadingScreen.Load(ScreenManager, false, null, new BackgroundScreen(), new MainMenuScreen(),
                    new MessageBoxScreen("OMG !!!\n\nI Couldn't find any level to load!\nWhat happend here? :(", false, false));
            }

            ScreenManager.Game.ResetElapsedTime();
        }

        /// <summary>
        /// Loads all Towers.
        /// </summary>
        /// <param name="directory">Directory where to load the Towers from.</param>
        private void LoadTowers(string directory)
        {
            string[] files = Directory.GetFiles(directory, "*.xml");
            towers = new List<TowerInfo>(files.Length);

            foreach (string file in files)
            {
                XmlDocument xmlFile = new XmlDocument();
                xmlFile.Load(file);

                XmlNode towerNode = xmlFile.GetElementsByTagName("tower")[0];
                if (towerNode != null)
                {
                    XmlNode towerDataNode = towerNode.SelectSingleNode("data");
                    if (towerDataNode != null)
                    {
                        string towerName = XmlHelper.ReadAttribute<string>(towerNode, "name", "no name");
                        string towerTextureFile = Path.Combine(directory, XmlHelper.ReadAttribute<string>(towerNode, "texture", ""));
                        Texture2D towerTexture = null;
                        if (File.Exists(towerTextureFile))
                        {
                            towerTexture = Texture2D.FromFile(ScreenManager.GraphicsDevice, towerTextureFile);
                        }
                        Color? towerColor = XmlHelper.ReadColor(towerDataNode.SelectSingleNode("color"), null);
                        Vector2? towerSize = XmlHelper.ReadVector2(towerDataNode.SelectSingleNode("size"), null);
                        XmlNode towerPurchaseNode = towerDataNode.SelectSingleNode("purchase");
                        if (towerPurchaseNode != null)
                        {
                            XmlNodeList towerUpgradeNodes = towerDataNode.SelectNodes("upgrade");
                            int maxUpgradeLevel = 0;
                            if (towerUpgradeNodes != null)
                            {
                                maxUpgradeLevel = towerUpgradeNodes.Count;
                            }
                            float[] range = new float[maxUpgradeLevel + 1];
                            int[] costs = new int[maxUpgradeLevel + 1];
                            int i = 0;
                            range[0] = XmlHelper.ReadAttribute<float>(towerPurchaseNode, "range", 1.0f);
                            costs[0] = XmlHelper.ReadAttribute<int>(towerPurchaseNode, "costs", 0);
                            foreach (XmlNode node in towerUpgradeNodes)
                            {
                                i++;
                                range[i] = XmlHelper.ReadAttribute<float>(node, "range", 1.0f);
                                costs[i] = XmlHelper.ReadAttribute<int>(node, "costs", 0);
                            }
                            string towerType = XmlHelper.ReadAttribute<string>(towerNode, "type", "");
                            if (towerType == "WeaponTower")
                            {
                                XmlNode towerProjectileNode = towerNode.SelectSingleNode("projectile");
                                if (towerProjectileNode != null)
                                {
                                    float[] damage = new float[maxUpgradeLevel + 1];
                                    float[] fireRate = new float[maxUpgradeLevel + 1];
                                    float[] splashRange = new float[maxUpgradeLevel + 1];
                                    damage[0] = XmlHelper.ReadAttribute<float>(towerPurchaseNode, "damage", 1.0f);
                                    fireRate[0] = XmlHelper.ReadAttribute<float>(towerPurchaseNode, "fireRate", 1.0f);
                                    splashRange[0] = XmlHelper.ReadAttribute<float>(towerPurchaseNode, "splashRange", 0.0f);
                                    i = 0;
                                    foreach (XmlNode node in towerUpgradeNodes)
                                    {
                                        i++;
                                        damage[i] = XmlHelper.ReadAttribute<float>(node, "damage", 1.0f);
                                        fireRate[i] = XmlHelper.ReadAttribute<float>(node, "fireRate", 1.0f);
                                        splashRange[i] = XmlHelper.ReadAttribute<float>(node, "splashRange", 0.0f);
                                    }

                                    string projectileTextureFile = Path.Combine(directory, XmlHelper.ReadAttribute<string>(towerProjectileNode, "texture", ""));
                                    Texture2D projectileTexture = null;
                                    if (File.Exists(projectileTextureFile))
                                    {
                                        projectileTexture = Texture2D.FromFile(ScreenManager.GraphicsDevice, projectileTextureFile);
                                    }
                                    float projectileSpeed = XmlHelper.ReadAttribute<float>(towerProjectileNode, "speed", 1.0f);
                                    Color? projectileColor = XmlHelper.ReadColor(towerProjectileNode.SelectSingleNode("color"), null);
                                    Vector2? projectileSize = XmlHelper.ReadVector2(towerProjectileNode.SelectSingleNode("size"), null);

                                    towers.Add(new WeaponTowerInfo(towerName, towerTexture, towerColor, towerSize, maxUpgradeLevel, range, costs, damage,
                                        fireRate, splashRange, new ProjectileInfo(projectileTexture, projectileColor, projectileSize, projectileSpeed)));
                                }
                            }
                            else if (towerType == "SupportTower")
                            {
                                float[] rangeMultiplier = new float[maxUpgradeLevel + 1];
                                float[] damageMultiplier = new float[maxUpgradeLevel + 1];
                                float[] fireRateMultiplier = new float[maxUpgradeLevel + 1];
                                float[] splashRangeMultiplier = new float[maxUpgradeLevel + 1];
                                rangeMultiplier[0] = XmlHelper.ReadAttribute<float>(towerPurchaseNode, "rangeMultiplier", 1.0f);
                                damageMultiplier[0] = XmlHelper.ReadAttribute<float>(towerPurchaseNode, "damageMultiplier", 1.0f);
                                fireRateMultiplier[0] = XmlHelper.ReadAttribute<float>(towerPurchaseNode, "fireRateMultiplier", 1.0f);
                                splashRangeMultiplier[0] = XmlHelper.ReadAttribute<float>(towerPurchaseNode, "splashRangeMultiplier", 1.0f);
                                i = 0;
                                foreach (XmlNode node in towerUpgradeNodes)
                                {
                                    i++;
                                    rangeMultiplier[i] = XmlHelper.ReadAttribute<float>(node, "rangeMultiplier", 1.0f);
                                    damageMultiplier[i] = XmlHelper.ReadAttribute<float>(node, "damageMultiplier", 1.0f);
                                    fireRateMultiplier[i] = XmlHelper.ReadAttribute<float>(node, "fireRateMultiplier", 1.0f);
                                    splashRangeMultiplier[i] = XmlHelper.ReadAttribute<float>(node, "splashRangeMultiplier", 1.0f);
                                }

                                towers.Add(new SupportTowerInfo(towerName, towerTexture, towerColor, towerSize, maxUpgradeLevel, range,
                                    costs, rangeMultiplier, damageMultiplier, fireRateMultiplier, splashRangeMultiplier));
                            }
                        }
                    }
                }
            }

            towers.Sort(TowerInfoCompare);
        }

        /// <summary>
        /// Sort algorithm for the Tower list.
        /// </summary>
        /// <param name="a"></param>
        /// <param name="b"></param>
        /// <returns></returns>
        private static int TowerInfoCompare(TowerInfo a, TowerInfo b)
        {
            if (a.Type == b.Type)
            {
                if (a.Name == b.Name)
                {
                    return 0;
                }
                else
                {
                    // if the Tower types are equal sort they after their names.
                    return String.Compare(a.Name, b.Name);
                }
            }
            else
            {
                 // because WeaponTower should be before SupportTower. ;)
                return String.Compare(b.Type.ToString(), a.Type.ToString());
            }
        }

        /// <summary>
        /// Loads all Levels.
        /// </summary>
        /// <param name="directory">Directory where to load the Levels from.</param>
        private void LoadLevels(string directory)
        {
            string[] files = Directory.GetFiles(directory, "*.xml");
            Array.Sort(files);

            levels = new List<Level>(files.Length);

            foreach (string file in files)
            {
                XmlDocument xmlFile = new XmlDocument();
                xmlFile.Load(file);

                XmlNode levelPathNode = xmlFile.GetElementsByTagName("path")[0];
                XmlNode levelBackgroundNode = xmlFile.GetElementsByTagName("background")[0];
                XmlNode levelColorNode = xmlFile.GetElementsByTagName("color")[0];

                Texture2D backgroundTexture = null;
                Color cursorColor = Color.Black, towerColor = Color.Black, textColor = Color.Black, errorColor = Color.Red;

                // only load the file if there are >= 2 points in the path
                if (levelPathNode.ChildNodes.Count < 2)
                {
                    continue;
                }

                if (levelBackgroundNode != null)
                {
                    string backgroundTexturePath = Path.Combine(directory, XmlHelper.ReadAttribute<string>(levelBackgroundNode, "texture", ""));
                    if(File.Exists(backgroundTexturePath))
                    {
                        backgroundTexture = Texture2D.FromFile(ScreenManager.GraphicsDevice, backgroundTexturePath);
                    }
                }

                if (levelColorNode != null)
                {
                    cursorColor = (Color)XmlHelper.ReadColor(levelColorNode.SelectSingleNode("cursor"), Color.Black);
                    towerColor = (Color)XmlHelper.ReadColor(levelColorNode.SelectSingleNode("tower"), Color.Black);
                    textColor = (Color)XmlHelper.ReadColor(levelColorNode.SelectSingleNode("text"), Color.Black);
                    errorColor = (Color)XmlHelper.ReadColor(levelColorNode.SelectSingleNode("error"), Color.Red);
                }

                Vector2[] levelPath = new Vector2[levelPathNode.ChildNodes.Count];
                int nodeCounter = 0;
                foreach (XmlNode node in levelPathNode)
                {
                    levelPath[nodeCounter++] = new Vector2(
                        XmlHelper.ReadAttribute<float>(node, "x", 0.0f),
                        XmlHelper.ReadAttribute<float>(node, "y", 0.0f));
                }

                levels.Add(new Level(player, backgroundTexture, cursorColor, towerColor, textColor,
                    errorColor, soundBank, levelPath));
            }
        }

        /// <summary>
        /// Unload graphics content used by the game.
        /// </summary>
        public override void UnloadContent()
        {
            content.Unload();
        }

        #endregion

        #region Update and Draw

        /// <summary>
        /// Updates the state of the game. This method checks the GameScreen.IsActive
        /// property, so the game will stop updating when the pause menu is active,
        /// or if you tab away to a different application.
        /// </summary>
        public override void Update(GameTime gameTime, bool otherScreenHasFocus,
                                                       bool coveredByOtherScreen)
        {
            base.Update(gameTime, otherScreenHasFocus, coveredByOtherScreen);

            if (IsActive)
            {
                float elapsedTime = (float)gameTime.ElapsedGameTime.TotalSeconds;

                if (!isPaused)
                {
                    if (currentLevel.Player.Lives <= 0)
                    {
                        string gameOverText = "Game Over!\n\n"
                            + "Well not really! lol\n"
                            + "Because this is still in beta,\n"
                            + "you got 10 extra lives for free! xD";
                        ScreenManager.AddScreen(new MessageBoxScreen(gameOverText, false, true));
                        currentLevel.Player.Lives = 10;
                    }

                    if (isBulletTime)
                    {
                        currentLevel.Update(elapsedTime / 10.0f);
                    }
                    else
                    {
                        currentLevel.Update(elapsedTime);
                    }
                }

                circleRotationFactor += elapsedTime;
                if (circleRotationFactor >= 1.0f)
                {
                    circleRotationFactor = 0.0f;
                }

                if (gameplayState == GameplaySate.Place)
                {
                    currentTower.Tower.Position = mousePosition;
                    towerCircle = new Circle(mousePosition, currentTower.Tower.Range, 32, true,
                        circleRotationFactor * MathHelper.PiOver4, 2.0f, currentLevel.TowerColor);

                    currentTextBlinkTime += elapsedTime;
                    if (currentTextBlinkTime >= textBlinkTime)
                    {
                        currentTextBlinkTime = 0.0f;
                    }
                }
                else // gameplayState == GameplaySate.Select
                {
                    if (selectCursorPulsationDirection)
                    {
                        currentSelectCursorPulsation -= selectCursorPulsation * elapsedTime;
                        if (currentSelectCursorPulsation <= 0.0f)
                        {
                            selectCursorPulsationDirection = false;
                        }
                    }
                    else
                    {
                        currentSelectCursorPulsation += selectCursorPulsation * elapsedTime;
                        if (currentSelectCursorPulsation >= selectCursorPulsation)
                        {
                            selectCursorPulsationDirection = true;
                        }
                    }
                    selectCursor = new Circle(mousePosition, selectCursorRadius + currentSelectCursorPulsation, 16, true,
                        circleRotationFactor * MathHelper.PiOver2, 3.0f - currentSelectCursorPulsation / selectCursorPulsation * 2.0f,
                        currentLevel.CursorColor);
                }
            }
        }

        /// <summary>
        /// Lets the game respond to player input. Unlike the Update method,
        /// this will only be called when the gameplay screen is active.
        /// </summary>
        public override void HandleInput(InputState input)
        {
            if (input.IsPauseGame())
            {
                ScreenManager.AddScreen(new PauseMenuScreen());
            }
            else
            {
                if (gameplayState == GameplaySate.Place)
                {
                    // collision detection with the mouse cursor
                    canTowerPlaceHere = true;
                    foreach (Tower tower in currentLevel.Towers)
                    {
                        if ((tower.Position - input.CurrentMousePosition).Length() < collisonDistanceBetweenTowers + (tower.Info.Size.X + currentTower.Size.X) / 2.0f)
                        {
                            canTowerPlaceHere = false;
                            collisionPoint = tower.Position;
                            break;
                        }
                    }
                    // if the cursor is already colliding with a tower, we don't need to check against the path
                    if (canTowerPlaceHere)
                    {
                        foreach (Line line in currentLevel.Path.Lines)
                        {
                            if (Calc.DistancePointLine(input.CurrentMousePosition, line) < collisonDistanceTowerPath + currentTower.Size.X / 2.0)
                            {
                                canTowerPlaceHere = false;
                                collisionPoint = Calc.ClosestPointOnLine(input.CurrentMousePosition, line);
                                break;
                            }
                        }
                    }

                    if (input.IsNewKeyPress(Keys.Right) || input.CurrentMouseState.ScrollWheelValue < input.LastMouseState.ScrollWheelValue)
                    {
                        if (++towerIndex >= towers.Count)
                        {
                            towerIndex = 0;
                        }
                        currentTower = towers[towerIndex];
                    }
                    else if (input.IsNewKeyPress(Keys.Left) || input.CurrentMouseState.ScrollWheelValue > input.LastMouseState.ScrollWheelValue)
                    {
                        if (--towerIndex < 0)
                        {
                            towerIndex = towers.Count - 1;
                        }
                        currentTower = towers[towerIndex];
                    }
                    else if (canTowerPlaceHere && input.CurrentMouseState.LeftButton == ButtonState.Pressed)
                    {
                        if (currentTower.Costs[0] <= player.Money)
                        {
                            currentLevel.addTower(currentTower, input.CurrentMousePosition);
                        }
                    }
                }
                else // gameplayState == GameplaySate.Select
                {
                    if (input.IsNewButtonPress(MouseButtons.LeftButton))
                    {
                        currentLevel.SelectedTower = null;
                        foreach (Tower tower in currentLevel.Towers)
                        {
                            if ((tower.Position - input.CurrentMousePosition).Length() < selectCursorRadius)
                            {
                                currentLevel.SelectedTower = tower;
                                break;
                            }
                        }
                    }
                }

                if (currentLevel.SelectedTower != null)
                {
                    if (input.IsNewKeyPress(Keys.U) && currentLevel.SelectedTower.UpgradeLevel < currentLevel.SelectedTower.Info.MaxUpgradeLevel)
                    {
                        if (currentLevel.SelectedTower.Info.Costs[currentLevel.SelectedTower.UpgradeLevel + 1] < currentLevel.Player.Money)
                        {
                            currentLevel.SelectedTower.Upgrade();
                        }
                    }
                    else if (input.IsNewKeyPress(Keys.S))
                    {
                        currentLevel.removeTower();
                    }
                }

                if (input.IsNewKeyPress(Keys.F1))
                {
                    string helpMessage = "Help\n\n"
                        + "Space / right-click: Switch between place- and select-mode.\n"
                        + "Left/right / mouse wheel: Select Tower (only in place-mode)\n"
                        + "Left-click: Place a new tower (in place-mode)\n"
                        + "                 Select a tower (in select-mode)\n\n"
                        + "U: Upgrade Tower (+ CTRL >> Upgrade all to max.)\n"
                        + "S: Sell Tower (+ CTRL >> Sell all)\n"
                        + "N: Next Wave\n\n"
                        + "ESC: Pause menu\n\n"
                        + "F2: DrawEnemies (" + Level.DrawEnemies.ToString() + ")\n"
                        + "F3: DrawTowers (" + Level.DrawTowers.ToString() + ")\n"
                        + "F4: DrawTowerCircles (" + Level.DrawTowerCircles.ToString() + ")\n"
                        + "F5: DrawTowerTargetLine (" + Level.DrawTowerTargetLine.ToString() + ")\n"
                        + "F6: DrawProjectiles (" + Level.DrawProjectiles.ToString() + ")\n"
                        + "F7: DrawText (" + Level.DrawText.ToString() + ")\n"
                        + "F8: DrawPath (" + Level.DrawPath.ToString() + ")\n"
                        + "F9: DrawBackgroundTexture (" + Level.DrawBackgroundTexture.ToString() + ")\n"
                        + "F11: BulletTime (" + isBulletTime.ToString() + ")\n"
                        + "F12: Next Level\n"
                        + "M: add 1.000.000 Credits ;)\n"
                        + "Pause: Pause the game update (debug).";

                    ScreenManager.AddScreen(new MessageBoxScreen(helpMessage, true, true));
                }
                else if (input.IsNewKeyPress(Keys.Space) || input.IsNewButtonPress(MouseButtons.RightButton))
                {
                    gameplayState++;
                    if (gameplayState > GameplaySate.Select)
                    {
                        gameplayState = GameplaySate.Place;
                    }
                }
                else if (input.IsNewKeyPress(Keys.N))
                {
                    currentLevel.NextWave();
                }
                else if (input.IsNewKeyPress(Keys.Tab))
                {
                    MainGame.Console.Open(Keys.Tab);
                }
                else if (input.IsNewKeyPress(Keys.F2))
                {
                    Level.DrawEnemies = !Level.DrawEnemies;
                }
                else if (input.IsNewKeyPress(Keys.F3))
                {
                    Level.DrawTowers = !Level.DrawTowers;
                }
                else if (input.IsNewKeyPress(Keys.F4))
                {
                    Level.DrawTowerCircles = !Level.DrawTowerCircles;
                }
                else if (input.IsNewKeyPress(Keys.F5))
                {
                    Level.DrawTowerTargetLine = !Level.DrawTowerTargetLine;
                }
                else if (input.IsNewKeyPress(Keys.F6))
                {
                    Level.DrawProjectiles = !Level.DrawProjectiles;
                }
                else if (input.IsNewKeyPress(Keys.F7))
                {
                    Level.DrawText = !Level.DrawText;
                }
                else if (input.IsNewKeyPress(Keys.F8))
                {
                    if (Level.DrawPath == true)
                        Level.DrawPath = false;
                    else if (Level.DrawPath == false)
                        Level.DrawPath = null;
                    else
                        Level.DrawPath = true;
                }
                else if (input.IsNewKeyPress(Keys.F9))
                {
                    Level.DrawBackgroundTexture = !Level.DrawBackgroundTexture;
                }
                else if (input.IsNewKeyPress(Keys.F11))
                {
                    isBulletTime = !isBulletTime;
                }
                else if (input.IsNewKeyPress(Keys.F12))
                {
                    if (++levelIndex >= levels.Count)
                    {
                        levelIndex = 0;
                    }
                    currentLevel = levels[levelIndex];
                }
                else if (input.IsNewKeyPress(Keys.M))
                {
                    player.Money += 1000000;
                    MainGame.Console.Log("1,000,000 credits added");
                }
                else if (input.CurrentKeyboardState.IsKeyDown(Keys.LeftControl) && input.IsNewKeyPress(Keys.U))
                {
                    // upgrade all towers to max level
                    foreach (Tower tower in currentLevel.Towers)
                    {
                        while (tower.UpgradeLevel < tower.Info.MaxUpgradeLevel)
                        {
                            tower.Upgrade();
                        }
                    }
                }
                else if (input.CurrentKeyboardState.IsKeyDown(Keys.LeftControl) && input.IsNewKeyPress(Keys.S))
                {
                    // sell all towers
                    while (currentLevel.Towers.Count > 0)
                    {
                        currentLevel.SelectedTower = currentLevel.Towers[0];
                        currentLevel.removeTower();
                    }
                }
                else if (input.IsNewKeyPress(Keys.Pause))
                {
                    isPaused = !isPaused;
                }
                else if (input.IsNewKeyPress(Keys.C))
                {
                    MainGame.Console.Bounds = new Rectangle(50, 150, 600, 350);
                }
                else if (input.IsNewKeyPress(Keys.X))
                {
                    MainGame.Console.Bounds = new Rectangle(100, 250, 350, 100);
                }
                else if (input.IsNewKeyPress(Keys.T))
                {
                    MainGame.Console.BackgroundTexture = circleTexture;
                    MainGame.Console.BackgroundColor = Color.Red;
                }

                mousePosition = input.CurrentMousePosition;
            }
        }

        /// <summary>
        /// Draws the gameplay screen.
        /// </summary>
        public override void Draw(GameTime gameTime)
        {
            if (!IsExiting)
            {
                float elapsedTime = (float)gameTime.ElapsedGameTime.TotalSeconds;
                ScreenManager.GraphicsDevice.Clear(ClearOptions.Target, Color.White, 0.0f, 0);

                currentLevel.Draw(elapsedTime, debugFont);

                SpriteManager.Begin();

                if (gameplayState == GameplaySate.Place)
                {
                    foreach (Line line in towerCircle.Lines)
                    {
                        SpriteManager.Draw(line.LineSprite);
                    }

                    string towerText = currentTower.ToString();
                    SpriteManager.SpriteBatch.DrawString(gameFont, towerText, currentTower.Tower.Position
                        - gameFont.MeasureString(towerText) / 2.0f + new Vector2(0.0f, 25.0f), currentLevel.TextColor);

                    if (canTowerPlaceHere)
                    {
                        if (currentTower.Costs[0] > player.Money && currentTextBlinkTime < textBlinkTime / 2.0f)
                        {
                            string moneyText = "insufficient funds!";
                            SpriteManager.SpriteBatch.DrawString(gameFont, moneyText, currentTower.Tower.Position
                                - gameFont.MeasureString(moneyText) / 2.0f - new Vector2(0.0f, 25.0f), currentLevel.ErrorColor);
                        }
                    }
                    else
                    {
                        SpriteManager.Draw(new Sprite(circleTexture, currentTower.Tower.Position, null, new Color(currentLevel.ErrorColor, 96),
                            0.0f, new Vector2(512.0f), new Vector2(currentTower.Range[0] / 512.0f), SpriteEffects.None, 0.0f));

                        // collision helper line
                        SpriteManager.Draw(new Line(currentTower.Tower.Position, collisionPoint, 2.0f, currentLevel.ErrorColor).LineSprite);

                        if (currentTextBlinkTime < textBlinkTime / 2.0f)
                        {
                            string cantPlaceHereText = "can't place here!";
                            SpriteManager.SpriteBatch.DrawString(gameFont, cantPlaceHereText, currentTower.Tower.Position
                                - gameFont.MeasureString(cantPlaceHereText) / 2.0f - new Vector2(0.0f, 25.0f), currentLevel.ErrorColor);
                        }
                    }

                    SpriteManager.Draw(currentTower.Tower);

                    string towerCostsText = currentTower.Costs[0].ToString();
                    SpriteManager.SpriteBatch.DrawString(debugFont, towerCostsText, currentTower.Tower.Position
                        - debugFont.MeasureString(towerCostsText) / 2.0f, Color.White);
                }
                else // gameplayState == GameplaySate.Select
                {
                    foreach (Line line in selectCursor.Lines)
                    {
                        SpriteManager.Draw(line.LineSprite);
                    }
                }

                SpriteManager.SpriteBatch.DrawString(guiFont, "Lives: " + currentLevel.Player.Lives.ToString() + ", Money: " + currentLevel.Player.Money.ToString("n") + ", Points: " + currentLevel.Player.Points.ToString("0,0")
                    + "\nWave: " + currentLevel.Wave.ToString() + " (next wave in " + Math.Round(currentLevel.TimeUntilNextWave, 0).ToString() + " seconds, ActiveWaves: " + currentLevel.Waves.Count.ToString() + ")"
                    + "\nEnemies: " + currentLevel.Enemies.Count.ToString() + " (Killed: " + currentLevel.EnemiesKilled.ToString()
                    + ", DestinationReached: " + currentLevel.EnemiesDestinationReached.ToString() + ")"
                    + "\nTowers: " + currentLevel.Towers.Count.ToString(),
                    new Vector2(425.0f, 5.0f), currentLevel.TextColor);
                SpriteManager.SpriteBatch.DrawString(arial, "SelectedTower = " + (currentLevel.SelectedTower != null ? currentLevel.SelectedTower.ToString() : "null"),
                    new Vector2(5.0f, ScreenManager.GraphicsDevice.Viewport.Height - 16), currentLevel.TextColor);

                if (isPaused)
                {
                    string pauseText = "Paused";
                    Vector2 pauseTextSize = ScreenManager.Font.MeasureString(pauseText) / 2.0f;
                    SpriteManager.SpriteBatch.DrawString(ScreenManager.Font, pauseText,
                        new Vector2(ScreenManager.GraphicsDevice.Viewport.Width / 2 - pauseTextSize.X,
                            ScreenManager.GraphicsDevice.Viewport.Height / 2 - pauseTextSize.Y), currentLevel.ErrorColor);
                }

                SpriteManager.End();

                // If the game is transitioning on or off, fade it out to black.
                if (TransitionPosition > 0)
                {
                    ScreenManager.FadeBackBufferToBlack(255 - TransitionAlpha);
                }
            }
        }

        #endregion
    }

    public enum GameplaySate : int
    {
        /// <summary>
        /// Place new towers.
        /// </summary>
        Place,
        /// <summary>
        /// Select a tower.
        /// </summary>
        Select
    }
}
